package com.m4u.teste;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Root;

import org.apache.log4j.Logger;

import com.m4u.entity.Cliente;
import com.m4u.entity.Telefone;

public class Main {

    static final Logger logger = Logger.getLogger(Main.class);

    public static void main(String[] args) throws Exception {
        logger.debug("Inicio...");
        // queryApi();
        // lockOtimista();
        // duasDependenciasParaUmaMesmaClasse();
        // schemaExport();
        queryCache();
    }

    @SuppressWarnings("unchecked")
    static void queryApi() throws Exception {

        // Insere um cliente...
        duasDependenciasParaUmaMesmaClasse();

        log("");
        log(" ----------------------------------------------------------------- ");

        EntityManager em = createEntityManager();
        CriteriaBuilder crtBuilder = em.getCriteriaBuilder();

        CriteriaQuery<Cliente> query = crtBuilder.createQuery(Cliente.class);

        Root<Cliente> cliente = query.from(Cliente.class);
        cliente.joinSet("telefones", JoinType.INNER);
        cliente.joinSet("telefonesCel", JoinType.INNER);

        query.select(cliente);

        List<Cliente> clientes = em.createQuery(query).getResultList();
        log(clientes);
        for (Cliente c : clientes) {
            log("cliente[].getTelefones(): " + c.getTelefones());
            log("cliente[].getTelefonesCel(): " + c.getTelefonesCel());
        }

        log(" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ");
        Query q = em.createQuery("select c from Cliente c join c.telefones join c.telefonesCel");
        clientes = q.getResultList();
        log(clientes + "\n\n");

        Set<Cliente> clientesSet = new HashSet<Cliente>(clientes);

        for (Cliente c : clientesSet) {
            log("cliente[].getTelefones(): " + c.getTelefones());
            log("cliente[].getTelefonesCel(): " + c.getTelefonesCel());
        }
        log(clientesSet);
    }

    @SuppressWarnings("unchecked")
    static void queryCache() {
        // Inserindo um novo cliente...
        EntityManager em = createEntityManager();
        em.getTransaction().begin();

        Cliente c = new Cliente();
        c.setNome("David Lock");

        em.persist(c);
        em.getTransaction().commit();
        em.close();

        //
        em = createEntityManager();
        Query q = em.createQuery("from Cliente where nome like :nome").setParameter("nome", "%");
        q.setHint("org.hibernate.cacheable", true);
        List<Cliente> clientes = q.getResultList();
        log("clientes: " + clientes);

        q = em.createQuery("from Cliente where nome like :nome").setParameter("nome", "%");
        q.setHint("org.hibernate.cacheable", true);
        clientes = q.getResultList();
        log("clientes2: " + clientes);

        em.getTransaction().begin();
        clientes.get(0).setNome("hbaksjdbksjhaksd");
        em.getTransaction().commit();

        q = em.createQuery("from Cliente where nome like :nome").setParameter("nome", "%");
        q.setHint("org.hibernate.cacheable", true);
        clientes = q.getResultList();
        log("clientes2: " + clientes);

    }

    static void schemaExport() throws Exception {
        SchemaGenerator gen = new SchemaGenerator("com.m4u.entity");
        gen.generate("org.hibernate.dialect.SQLServerDialect");
        gen.generate("org.hibernate.dialect.MySQLDialect");
    }

    static void lockOtimista() {

        // Inserindo um novo cliente...
        EntityManager em = createEntityManager();
        em.getTransaction().begin();

        Cliente c = new Cliente();
        c.setNome("David Lock");

        em.persist(c);
        em.getTransaction().commit();
        em.close();

        // em1 pega o cliente 1
        EntityManager em1 = createEntityManager();
        Cliente c1 = em1.find(Cliente.class, 1);

        // em2 pega o mesmo cliente (cliente 1)
        EntityManager em2 = createEntityManager();
        Cliente c2 = em2.find(Cliente.class, 1);

        // em1 atualiza o cliente 1
        c1.setNome(c1.getNome() + " em 1");
        log("em1:cliente:version:antes de salvar => " + c1.getVersion().getTime());
        em1.getTransaction().begin();
        em1.persist(c1);
        em1.getTransaction().commit();
        log("em1:cliente:version:depois de salvar => " + c1.getVersion().getTime());

        // em2 tambem tenta atualizar o mesmo cliente, em seguida
        c2.setNome(c2.getNome() + " em 2");
        em2.getTransaction().begin();
        log("em2:cliente:version:antes de salvar => " + c2.getVersion().getTime());
        em2.persist(c2);
        em2.getTransaction().commit();
        log("em2:cliente:version:depois de salvar => " + c2.getVersion().getTime());
    }

    static void duasDependenciasParaUmaMesmaClasse() {

        // Inserindo...
        EntityManager em = createEntityManager();

        em.getTransaction().begin();

        Cliente c = new Cliente();
        c.setNome("cliente02");
        c.getTelefones().add(new Telefone("02-888888"));
        c.getTelefones().add(new Telefone("02-8888111"));
        c.getTelefonesCel().add(new Telefone("02-8888111-cel"));
        c.getTelefonesCel().add(new Telefone("02-8888222-cel"));
        c.getTelefonesCel().add(new Telefone("02-8888333-cel"));
        em.persist(c);

        int clienteId = c.getId();
        log(" clienteId: " + clienteId);

        em.getTransaction().commit();

        // Verificando...
        em = createEntityManager();
        c = em.find(Cliente.class, 1);
        log(" cliente.getTelefones(): " + c.getTelefones());
        log(" cliente.getTelefonesCel(): " + c.getTelefonesCel());

    }

    static EntityManager entityManager = null;

    static EntityManager createEntityManager() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("default");
        return emf.createEntityManager();
    }

    static void log(Object o) {
        logger.warn(" >>>>>>>>>>>>>>>> " + o);
    }

}
